package com.tomato.base.limit.redis.executor;

import com.tomato.base.limit.redis.algorithm.RateLimiterAlgorithm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Component;

import java.time.Instant;
import java.util.Arrays;
import java.util.List;

/**
 * 算法执行
 *
 * @author lizhifu
 * @date 2022/3/4
 */
@Component
public class RedisRateLimiter {
    private static final Logger log = LoggerFactory.getLogger(RedisRateLimiter.class);
    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    /**
     * 限流执行
     * @param rateLimiterBuilder
     */
    public void exe(final String key,RateLimiterBuilder rateLimiterBuilder){
        double replenishRate = rateLimiterBuilder.getReplenishRate();
        double burstCapacity = rateLimiterBuilder.getBurstCapacity();
        double requestCount = rateLimiterBuilder.getRequestCount();
        RateLimiterAlgorithm rateLimiterAlgorithm = rateLimiterBuilder.getRateLimiterAlgorithm();
        RedisScript<List<Long>> script = rateLimiterAlgorithm.getScript();
        // key 组合之后如下
        // 1 concurrent_rate_limiter.{test}.tokens
        // 2 concurrent_rate_limiter.{test}.timestamp
        List<String> keys = rateLimiterAlgorithm.getKeys(key);
        List<String> scriptArgs = Arrays.asList(doubleToString(replenishRate),  doubleToString(burstCapacity), doubleToString(Instant.now().getEpochSecond()), doubleToString(requestCount));
        log.info("RedisRateLimiter exe keys is {},scriptArgs is {}",keys,scriptArgs);
        // 第一个参数是是否被限流，第二个参数是剩余令牌数
        List<Long> rateLimitResponse = redisTemplate.execute(script,keys,scriptArgs.toArray());
        log.info("RedisRateLimiter exe rateLimitResponse:{}",rateLimitResponse);
    }

    private String doubleToString(final double param) {
        return String.valueOf(param);
    }
}
